package com.by.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.by.enums.ErrorCode;
import com.by.exception.BusinessException;
import com.by.mapper.ThumbMapper;
import com.by.model.dto.thumb.DoThumbDTO;
import com.by.model.entity.Blog;
import com.by.model.entity.Thumb;
import com.by.model.entity.User;
import com.by.service.BlogService;
import com.by.service.ThumbService;
import com.by.service.UserService;
import com.by.utils.RedisKeyUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * @author lzh
 */
@Service("thumbServiceDB")
@RequiredArgsConstructor
public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb> implements ThumbService {

    private final UserService userService;
    private final BlogService blogService;
    private final TransactionTemplate transactionTemplate;
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public Boolean doThumb(DoThumbDTO doThumbDTO, HttpServletRequest request) {
        if (doThumbDTO == null || doThumbDTO.getBlogId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long blogId = doThumbDTO.getBlogId();
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        // 加锁
        synchronized (loginUser.getId().toString().intern()) {
            transactionTemplate.execute(status -> {
                // 判断用户是否已点赞
                Boolean exists = this.hasThumb(blogId, loginUser.getId());
                if (exists) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "已点赞");
                }

                // 更新对应博客的点赞数
                boolean update = blogService.lambdaUpdate()
                        .eq(Blog::getId, blogId)
                        .setSql("thumb_count = thumb_count + 1")
                        .update();
                // 写入点赞记录
                Thumb thumb = new Thumb();
                thumb.setBlogId(blogId);
                thumb.setUserId(loginUser.getId());

                // 返回
                boolean success = update && this.save(thumb);

                // 点赞记录存入 Redis
                if (success) {
                    redisTemplate.opsForHash()
                            .put(RedisKeyUtils.getUserThumbKey(loginUser.getId()),
                                    blogId.toString(),
                                    thumb.getId());
                }
                // 更新成功才执行
                return success;
            });
        }
        return true;
    }

    @Override
    public Boolean undoThumb(DoThumbDTO doThumbDTO, HttpServletRequest request) {
        if (doThumbDTO == null || doThumbDTO.getBlogId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long blogId = doThumbDTO.getBlogId();
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        // 加锁
        synchronized (loginUser.getId().toString().intern()) {
            transactionTemplate.execute(status -> {
                // 判断用户是否未点赞
                Object thumbIdObject = redisTemplate.opsForHash()
                        .get(RedisKeyUtils.getUserThumbKey(loginUser.getId()), blogId.toString());
                if (thumbIdObject == null) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "未点赞");
                }
                Long thumbId = Long.valueOf(thumbIdObject.toString());

                // 更新对应博客的点赞数
                boolean update = blogService.lambdaUpdate()
                        .eq(Blog::getId, blogId)
                        .setSql("thumb_count = thumb_count - 1")
                        .update();

                // 返回
                boolean success = update && this.removeById(thumbId);
                if (success) {
                    redisTemplate.opsForHash()
                            .delete(RedisKeyUtils.getUserThumbKey(loginUser.getId()), blogId.toString());
                }
                return success;
            });
        }
        return true;
    }

    @Override
    public Boolean hasThumb(Long blogId, Long userId) {
        return redisTemplate.opsForHash()
                .hasKey(RedisKeyUtils.getUserThumbKey(userId), blogId.toString());
    }
}




